package com.bonc.clustering;

import java.util.ArrayList;
import java.util.List;

import com.apporiented.algorithm.clustering.AverageLinkageStrategy;
import com.apporiented.algorithm.clustering.Cluster;
import com.apporiented.algorithm.clustering.ClusteringAlgorithm;
import com.apporiented.algorithm.clustering.DefaultClusteringAlgorithm;
import com.bonc.vectorspace.model.EventCorpus;
import com.bonc.vectorspace.model.EventDocument;
import com.bonc.vectorspace.model.VectorSpaceModel;

/**
 * @author donggui@bonc.com.cn
 * @version 2016 2016年6月27日 下午4:18:53
 */
public class EventCluster {
	private static double AalphaParam = 0.6;	
	private static double DistanceThreshold = 0.70;
	
	public static Cluster runCluster(List<EventDocument> documents, List<Integer> indices){

		EventCorpus corpus = new EventCorpus(documents);
		VectorSpaceModel vectorSpace = new VectorSpaceModel(corpus);

		int instancenum = indices.size();
		String[] names = new String[instancenum];
		
		double[][] distances = new double[instancenum][instancenum];
		for (int i = 0; i < instancenum; i++){
			int row_idx = indices.get(i);
			EventDocument doci = corpus.getDocuments().get(row_idx);
			
			//instance names
			names[i] = doci.getDocId();
			
			//distance matrix
			for (int j = i+1; j< instancenum; j++){
				
				int col_idx = indices.get(j);
				EventDocument docj = corpus.getDocuments().get(col_idx);
				double similarity = vectorSpace.jaccardSimilarity(doci, docj);
				distances[i][j] = AalphaParam * (1-similarity) + (1-AalphaParam)*(j-i)/instancenum;
				distances[j][i] = distances[i][j];
				distances[i][i] = 0;
			}
		}	


		ClusteringAlgorithm alg = new DefaultClusteringAlgorithm();
		Cluster cluster = alg.performClustering(distances, names, new AverageLinkageStrategy());

		return cluster;
	}
	
	public static List<Cluster> getClustersInferior(Cluster fatherCluster){
		List<Cluster> clusters = new ArrayList<Cluster>();
		for(Cluster cluster:fatherCluster.getChildren()){ 
			if(cluster.getDistanceValue() < DistanceThreshold){
				clusters.add(cluster);
			}else{
				clusters.addAll(getClustersInferior(cluster));
			}
		}
		return clusters;
	}
}
